#include "raytracer.h"
#include "sphere.h"
#include "plane.h"
#include "cylinder.h"
#include "Metaball.h"
#include <math.h>
#pragma warning (disable : 4996 )
/*-<==>-----------------------------------------------------------------
/ Defines the scene
/----------------------------------------------------------------------*/
void CRayTracer::load () {


	/******************************************************************************
	RAYTRACING SCENE EXAMPLE - THIS SCENE WILL SHOW A METABALL COMPOSED OF 3 SPHERES 
	WITH WOOD TEXTURE AND ENVIRONMENT MAPPING
	*******************************************************************************/

	// Add the camera looking at the origin
	camera.setView (VECTOR(0, 0, -300), VECTOR (0,0,0));
	camera.setRenderParameters (1024,1024,40);

	//Define CubeMap
	//cubemap.init("Textures/alpup.tga","Textures/alpdown.tga","Textures/alpback.tga","Textures/alpforward.tga","Textures/alpright.tga","Textures/alpleft.tga");
	cubemap.init("Textures/stpetersup.tga","Textures/stpetersdown.tga","Textures/stpetersback.tga","Textures/stpetersforward.tga","Textures/stpetersright.tga","Textures/stpetersleft.tga");



	// Define some materials
	CMarbleMaterial * marble =  new CMarbleMaterial (COLOR (1, 1, 1), 0.1, 0.0, 1.3, 0.2,0.8,0.1);
	marble->setMarbleParams(0.2, 30, 75);
	materials["marble"]  = marble;

	CWoodMaterial * wood =  new CWoodMaterial (COLOR (0.7, 0.4, 0.2), 0.0, 0.0, 1.1, 0.2,0.8,0.1);
	wood->setWoodParams(40);
	materials["wood"]  = wood;

	CTurbMaterial * turbulence =  new CTurbMaterial (COLOR (0.4, 0.8, 0.6), 0.0, 0.0, 1.3, 0.2,0.8,0.1, 10);
	materials["turbulence"]  = turbulence;

	materials["blue"]    = new CSolidMaterial (COLOR (0.0, 0.2, 0.5),  0.1, 0.0, 1.1, 0.0,0.6,0.7);
	materials["red"]    = new CSolidMaterial (COLOR (0.8, 0.1, 0.1), 0.6, 0.0, 1.0, 0.0,0.4,0.7);
	materials["green"]    = new CSolidMaterial (COLOR (0.2, 0.8, 0.1), 0.5, 0.0, 1.1, 0.0,0.3,0.7);
	materials["yellow"]    = new CSolidMaterial (COLOR (0.9, 0.8, 0.1), 0.5, 0.0, 1.1, 0.0,0.3,0.7);
	materials["purple"]    = new CSolidMaterial (COLOR (0.8, 0.1, 0.8), 0.0, 0.7, 1.3, 0.0,0.3,0.7);
	materials["white"]  = new CSolidMaterial (COLOR (0.6, 0.6, 0.7), 0.0, 0.0, 1.1, 0.1,0.7,0.2);
	materials["mirror"]  = new CSolidMaterial (COLOR (0.7, 0.7, 0.7), 0.8, 0.0, 1.0, 0.2,0.4,1.0);
	materials["black"]  = new CSolidMaterial (COLOR (0.2, 0.2, 0.2), 0.7, 0.0, 1.0, 0.2,0.2,0.2);
	materials["composedMaterial"] = new CCheckerMaterial(materials["white"],materials["black"],5 );

	CSphere * s1 = new CSphere(12.0);
	s1->setLocation(VECTOR(20,0,0));
	s1->setMaterial(materials["green"]);
	s1->getMaterial()->setBumpMap(true, 0.1);

	CSphere * s2= new CSphere(12.0);
	s2->setLocation(VECTOR(-20,0,0));
	s2->setMaterial(materials["white"]);
	s2->getMaterial()->setBumpMap(true, 0.1);

	CSphere * s4 = new CSphere(30.0);
	s4->setLocation(VECTOR(0,0,0));
	s4->setMaterial(materials["red"]);

	std::vector<VECTOR> pointsSet=std::vector<VECTOR>();
	pointsSet.push_back(VECTOR(30,0,0));
	pointsSet.push_back(VECTOR(-30,0,0));
	pointsSet.push_back(VECTOR(0,30,0));

	std::vector<SCALAR> radiusSet=std::vector<SCALAR>();
	radiusSet.push_back(40);
	radiusSet.push_back(35);
	radiusSet.push_back(25);

	Metaball  * meta =new Metaball(pointsSet, radiusSet , 0.1);
	meta->setMaterial(materials["wood"]);
	objects.push_back(meta);


	// Add a single white light
	CLight *light2 = new CLight(VECTOR (0,0,-50), COLOR (1,1,1));
	lights.push_back (light2);
}

bool CRayTracer::loadSnowflake (const char *filename) {
	FILE *f = fopen (filename, "r");
	if (!f)
		return false;
	cubemap.init("Textures/stpetersup.tga","Textures/stpetersdown.tga","Textures/stpetersback.tga","Textures/stpetersforward.tga","Textures/stpetersright.tga","Textures/stpetersleft.tga");
	// Add the camera looking at the origin
	camera.setView (VECTOR(2.1, 1.7, 1.3), VECTOR (0,0,0));
	camera.setRenderParameters (1024,1024,45);

	// Define background color
	background_color = COLOR( 0.078, 0.361, 0.753 );

	// Add a two material
	materials["txt001"]    = new CSolidMaterial (COLOR (0.8, 0.6, 0.264), 0.0, 0.0, 1.0, 0.2,0.7,0.3);
	materials["txt002"]    = new CSolidMaterial (COLOR (0.5, 0.45, 0.35), 0.5, 0.0, 1.0, 0.2,0.7,0.3);

	// Add the ground
	CPlane *plane = new CPlane (VECTOR(0,1,0), -0.5);
	plane->setMaterial (materials["txt001"]);
	//objects.push_back (plane); 

	// This is a very simply parser!!
	while (!feof(f)) {
		char buf[512];
		fgets (buf, 511, f);
		if (strncmp (buf, "sphere", 6) == 0) {
			char material[64];
			double x,y,z, rad;
			sscanf (buf, "sphere %s %lf %lf %lf %lf\n", material, &rad, &x,&y,&z);
			CSphere *sph = new CSphere(rad);
			sph->setLocation (VECTOR(x,z,y));
			sph->setMaterial (materials["txt002"]);
			objects.push_back (sph);
		} 
	}

	// Add 3 white lights
	lights.push_back (new CLight(VECTOR ( 4, 3, 2), COLOR (1,1,1)));
	lights.push_back (new CLight(VECTOR ( 1,-4, 4), COLOR (1,1,1)));
	lights.push_back (new CLight(VECTOR (-3, 1, 5), COLOR (1,1,1)));

	fclose (f);
	return true;
}

void CRayTracer::renderAnimation (int num_frames)
{
	//double angle= 2*3.1416 / num_frames;
	//double delta = (float)120 / (float)num_frames;

	TSamplingMode smode = POINT_SAMPLING;
	//render n frames
	for(int i=0 ; i<num_frames ;i++)  
	{	
		std::cout << "Computing Frame: " << i << std::endl;
		//render frame
		render("animation", i, POINT_SAMPLING);
		//change the scene
		/*SCALAR x =camera.getLoc().x;
		SCALAR z =  camera.getLoc().z;
		SCALAR new_x = x*cos(angle) - z*sin(angle);
		SCALAR new_z = x*sin(angle) + z*cos(angle);
		VECTOR loc = VECTOR(new_x,camera.getLoc().y, new_z);
		camera.setView(loc, camera.getTarget());
		Metaball * metaball = (Metaball*)objects[0];
		metaball->centers[0] = metaball->centers[0] - VECTOR(delta,0,0);
		metaball->centers[1] = metaball->centers[1] - VECTOR(-delta,0,0);
		metaball->centers[2] = metaball->centers[2] - VECTOR(0,delta,0);*/

	}

}


/*-<==>-----------------------------------------------------------------
/ MAIN
/----------------------------------------------------------------------*/

int main(int argc, char **argv) {

	CRayTracer rt;

	// Default input scene
	const char *filename = "balls_3.txt";

	//POINT_SAMPLING | UNIFORM_SAMPLING | JITTERED_SAMPLING | ADAPTATIVE_SAMPLING.
	TSamplingMode smode = POINT_SAMPLING;

	// Use filename given as runtime argument
	if (argc > 1){
		filename = argv[1];
		rt.loadSnowflake(filename);
	}
	else
		rt.load();

	//Define whether ray tracer will use ambient occlusion or convetional shades.
	rt.ambientOcclusion = false;

	//Uncomment if using ambient occlusion:

	//rt.numOcclusionSamples = 64;
	//rt.occlusionAmount = 0.8;
	//rt.maxOcclusionDistance = 30;
	//rt.background_color = COLOR(0,0,0);

	//rt.renderAnimation(300);
	// Render...
	rt.render("example", 0, smode);
	// Show and print render statistics.
	rt.showStats("exmaple_statistics.txt");

	return 0;
}
